﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Data;


namespace Utilities.Common
{
    public class PropInfo
    {
        public PropertyInfo Item { get; set; }
        public bool IsId { get; set; }
        public string Name { get; set; }
        
        public bool NotSaveMark { get; set; }
        public string Field { get; set; }
        public bool IsClass { get; set; }
        public ClassInfo ClassInfo { get; set; }

        public ClassInfo Parent { get; set; }


        public object GetValue(object obj, bool getId)
        {
            if (getId)//si me pide el id...
            {
                //me fijo si es una clase (Estado por ej) y obtengo el id de la instancia
                if (IsClass)
                {
                    object oId = Item.GetGetMethod().Invoke(obj, null); //en oId tengo el objeto, obtengo el id
                    if (oId != null)
                    {
                        ClassInfo c = ClassInfoCache.GetClassInfo(oId); //este es un objeto Estado por ej, ahora obtengo el id de ese objeto
                        return c.Properties.PropId.GetValue(oId);
                    }
                }
                else
                {
#warning esto es un estado no valido, no puede pedirme el id de una propiedad q no es una clase
                    
                }
            }
           return GetValue(obj);

        }
        public object GetValue(object obj)
        {      
            //return  Item.GetGetMethod().Invoke(obj, null);
#warning controlar que proxy no sea null
            return Parent.Proxy.GetValue(Item.Name, obj);
        }
        public bool IsEmpty(object obj)
        {
            object val = GetValue(obj);
            if (val == null) return true;

            switch (Item.PropertyType.Name)
            {
                case "Boolean":
                case "Byte":
                case "SByte":
                case "Char":
                    return false;
#warning teerminar
                case "Decimal":
                case "Double":
                case "Single":
                case "Int32":
                case "UInt32":
                case "Int64":
                case "UInt64":
                case "Int16":
                case "UInt16":
                    return val.ToString() == "0";

                case "String":
                    if (val == null)
                    {
                        return true;
                    }
                    else
                    {
                        return (val == "");
                    }
                    
                
            }
            return true;
        }
        public void SetValue(object item, object value)
        {
            Item.SetValue(item, value, null);
        }

        public void SetValue(object item, DataRow dr)
        {
            //si no esta marcada como "no guardable" busco el valor
            object value = null;
            if (!NotSaveMark)
            {
                //si es una clase no puedo hacer nada, trato de levantarlo igual...
#warning revisar
               // if (Item.PropertyType.IsClass)
                if (IsClass)
                {
                    if (dr.Table.Columns.Contains(Field))
                    {
                        try
                        {
                            value = dr[Field];
                        }
                        catch { }
                    }
                }
                else
                {
                    try
                    {
                        value = dr[Field];
                    }
                    catch
                    {
#warning no se si deberia no avisar esta exception
                    }

                }
                
            }
            if (value == DBNull.Value) value = null;

            Item.SetValue(item,value,null);
        }

        internal static PropInfo GetPropertyInfo(ClassInfo classInfo, object obj, System.Reflection.PropertyInfo pPropiedad)
        {
            PropInfo info = new PropInfo() { Parent = classInfo , Name= pPropiedad.Name, Item=pPropiedad };
#warning revisar
            if (pPropiedad.PropertyType.BaseType.Name.StartsWith("List")) return null; //las colecciones las ignoro por el momento

            info.IsClass=  (pPropiedad.PropertyType.IsClass && pPropiedad.PropertyType.Name != "String") ;
            if(info.IsClass)
            {
                info.ClassInfo = ClassInfoCache.GetClassInfo(pPropiedad.GetGetMethod().Invoke(obj, null));
            }

            Attribute noSave = AttributeHelper.GetAttribute(obj, pPropiedad, typeof(NotSaveAttribute));
            //si no esta marcada como "no guardable" agrego la propiedad
            if (noSave == null)
            {
                info.NotSaveMark = false;
                //veo si lo tengo q guardar en otro campo
                Attribute atribute = AttributeHelper.GetAttribute(obj, pPropiedad, typeof(FieldAttribute));
                if (atribute != null)
                {
                    info.Field = ((FieldAttribute)atribute).FieldName;
                }
                else
                {
                    info.Field = pPropiedad.Name;
                }

                //controlo si el atributo esta marcado como id

                atribute = AttributeHelper.GetAttribute(obj, pPropiedad, typeof(IsIdAttribute));
                info.IsId = (atribute != null);

            }
            else
            {
                info.NotSaveMark = true;//o sea q no la tengo q guardar
            }
            return info;
        }
     
    }

    public class PropInfoManager : List<PropInfo>
    {        

        /// <summary>
        /// Permite acceso rapido a la propiedad Id.
        /// </summary>
        public PropInfo  PropId{ get; set; }
    }
}
